home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / oleo-1_4.lha / oleo-1.4 / graph.c < prev    next >
C/C++ Source or Header  |  1993-05-23  |  28KB  |  1,262 lines

  1. /*    Copyright (C) 1993 Free Software Foundation, Inc.
  2.  
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2, or (at your option)
  6. any later version.
  7.  
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11. GNU General Public License for more details.
  12.  
  13. You should have received a copy of the GNU General Public License
  14. along with this software; see the file COPYING.  If not, write to
  15. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  16.  
  17.  
  18.  
  19. #include <ctype.h>
  20. #include "global.h"
  21. #include "graph.h"
  22. #include "cmd.h"
  23. #include "line.h"
  24. #include "io-term.h"
  25. #include "info.h"
  26. #include "cell.h"
  27. #include "regions.h"
  28. #include "ref.h"
  29. #include "io-utils.h"
  30.  
  31. /* Parameters for the next graph that will be drawn. */
  32.  
  33. /* This determines the type and destination of the ouput.
  34.  * It should be the argument to a  `set term %s'.  For posctscript graphs,
  35.  * we slip in a `set output %s' as well.
  36.  */
  37. static struct line graph_term_cmd;
  38. static struct line graph_output_file;
  39.  
  40. #ifdef __STDC__
  41. typedef void (*plotter) (void);
  42. #else
  43. typedef void (*plotter) ();
  44. #endif
  45.  
  46. struct get_symbols_frame;
  47. struct write_data_frame;
  48. #ifdef __STDC__
  49. static void get_symbols_thunk (struct get_symbols_frame * fr,
  50.                    CELL * cell, CELLREF r, CELLREF c);
  51. static void write_data_thunk (struct write_data_frame * fr,
  52.                   CELL * y_cell, CELLREF r, CELLREF c) ;
  53. static void spew_gnuplot (FILE  * fp, struct line * data_files, char * dir,
  54.               char * dbase); 
  55. static void spew_for_x (void);
  56. static void spew_for_ps (void);
  57. #else
  58. static void get_symbols_thunk ();
  59. static void write_data_thunk ();
  60. static void spew_gnuplot ();
  61. static void spew_for_x ();
  62. static void spew_for_ps ();
  63. #endif
  64.  
  65. static plotter plot_fn = 0;
  66.  
  67. char * gnuplot_program = "gnuplot";
  68. char * gnuplot_shell = "/bin/sh";
  69. char * rm_program = "/bin/rm";
  70.  
  71. char * graph_axis_name [graph_num_axis] =
  72. {
  73.   "x", "y"
  74. };
  75.  
  76. char *
  77. graph_order_name [graph_num_orders] =
  78. {
  79.   "rows",
  80.   "columns",
  81. };
  82.  
  83. char *graph_pair_order_name[graph_num_pair_orders] =
  84. {
  85.   "rows of hz pairs",
  86.   "rows of vt pairs",
  87.   "enumerated rows",
  88.   "cols of hz pairs",
  89.   "cols of vt pairs",
  90.   "enumerated cols"
  91. };
  92.  
  93. int graph_ornt_row_magic [graph_num_pair_orientations] = { 0, 1, 0 };
  94. int graph_ornt_col_magic [graph_num_pair_orientations] = { 1, 0, 0 };
  95.  
  96.  
  97. /* `set label %s' for each axis.
  98.  */
  99. static struct line graph_axis_title [graph_num_axis];
  100.  
  101. /* set logarithmic */
  102. static int graph_logness [graph_num_axis];
  103.  
  104. /* Arguments to `set range [%s:%s]' */
  105. static struct line graph_rng_lo [graph_num_axis];
  106. static struct line graph_rng_hi [graph_num_axis];
  107.  
  108. /* The ranges (if any) of the symbolic names
  109.  * for integer coordinates starting at 0.
  110.  * If none, these will have lr == NON_ROW.
  111.  */
  112. static struct rng graph_axis_symbols [graph_num_axis];
  113. static enum graph_ordering graph_axis_ordering [graph_num_axis];
  114.  
  115. /* Names to print along the axes */
  116. static struct rng graph_axis_labels [graph_num_axis];
  117. static enum graph_pair_ordering graph_axis_label_order [graph_num_axis];
  118.  
  119. /* Parameters for each dataset. */
  120. #define NUM_DATASETS 10
  121.  
  122. /* plot .... with %s */
  123. static struct line graph_style [NUM_DATASETS];
  124. static struct line graph_title [NUM_DATASETS];
  125. static struct rng graph_data [NUM_DATASETS];
  126. static enum graph_pair_ordering graph_data_order [graph_num_axis];
  127.  
  128.  
  129.  
  130.  
  131. #ifdef __STDC__
  132. enum graph_axis
  133. chr_to_axis (int c)
  134. #else
  135. enum graph_axis
  136. chr_to_axis (c)
  137.      int c;
  138. #endif
  139. {
  140.   if (isupper (c))
  141.     c = tolower (c);
  142.   switch (c)
  143.     {
  144.     case 'x':
  145.       return graph_x;
  146.     case 'y':
  147.       return graph_y;
  148.     }
  149.   io_error_msg ("Unkown graph-axis `%c' (try `x' or `y')", c);
  150.   return graph_x;        /* not reached, actualy. */
  151. }
  152.  
  153.  
  154. #ifdef __STDC__
  155. enum graph_ordering
  156. chr_to_graph_ordering (int c)
  157. #else
  158. enum graph_ordering
  159. chr_to_graph_ordering (c)
  160.      int c;
  161. #endif
  162. {
  163.   if (isupper (c))
  164.     c = tolower (c);
  165.   switch (c)
  166.     {
  167.     case 'r':
  168.       return graph_rows;
  169.     case 'c':
  170.       return graph_cols;
  171.     }
  172.   io_error_msg ("Unknown cell ordering `%c' (try `r' or `c').", c);
  173.   return graph_rows;        /* not reached */
  174. }
  175.  
  176. #ifdef __STDC__
  177. enum graph_pair_ordering
  178. chrs_to_graph_pair_ordering (int pair, int dir)
  179. #else
  180. enum graph_pair_ordering
  181. chrs_to_graph_pair_ordering (pair, dir)
  182.      int pair;
  183.      int dir;
  184. #endif
  185. {
  186.   int pair_offset;
  187.   if (isupper (pair))
  188.     pair = tolower (pair);
  189.   if (isupper (dir))
  190.     dir = tolower (dir);
  191.  
  192.   switch (pair)
  193.     {
  194.     case 'h':
  195.       pair_offset = graph_hz;
  196.       break;
  197.     case 'v':
  198.       pair_offset = graph_vt;
  199.       break;
  200.     case 'i':
  201.       pair_offset = graph_implicit;
  202.       break;
  203.     default:
  204.       pair_offset = graph_implicit;
  205.       io_error_msg
  206.     ("graph.c: invalid pair ording `%c' (wanted h, v, or i)", pair);
  207.       /* no deposit... */
  208.     }
  209.  
  210.   return PAIR_ORDER(chr_to_graph_ordering (dir), pair_offset);
  211. }
  212.  
  213. #ifdef __STDC__
  214. char *
  215. graph_quoted_str (char *str)
  216. #else
  217. char *
  218. graph_quoted_str (str)
  219.      char *str;
  220. #endif
  221. {
  222.   static struct line buf;
  223.   
  224.   set_line (&buf, "\"");
  225.   while (*str)
  226.     {
  227.       switch (*str)
  228.     {
  229.     case '"':
  230.       catn_line (&buf, "\\\"", 2);
  231.       break;
  232.     default:
  233.       catn_line (&buf, str, 1);
  234.       break;
  235.     }
  236.       ++str;
  237.     }
  238.   catn_line (&buf, "\"", 1);
  239.   return buf.buf;
  240. }
  241.  
  242.  
  243.  
  244. #ifdef __STDC__
  245. void
  246. graph_x11_mono (void)
  247. #else
  248. void
  249. graph_x11_mono ()
  250. #endif
  251. {
  252.   set_line (&graph_term_cmd, "x11 # b/w");
  253.   set_line (&graph_output_file, "");
  254.   plot_fn = spew_for_x;
  255. }
  256.  
  257.  
  258. #ifdef __STDC__
  259. void
  260. graph_x11_color (void)
  261. #else
  262. void
  263. graph_x11_color ()
  264. #endif
  265. {
  266.   set_line (&graph_term_cmd, "X11 # color");
  267.   set_line (&graph_output_file, "");
  268.   plot_fn = spew_for_x;
  269. }
  270.  
  271.  
  272. #ifdef __STDC__
  273. void
  274. graph_postscript (char * file, int kind, int spectrum, char * font, int pt_size)
  275. #else
  276. void
  277. graph_postscript (file, kind, spectrum, font, pt_size)
  278.      char * file;
  279.      int kind;
  280.      int spectrum;
  281.      char * font;
  282.      int pt_size;
  283. #endif
  284. {
  285.   if (isupper (kind))
  286.     kind = tolower (kind);
  287.   if (isupper (spectrum))
  288.     spectrum = tolower (spectrum);
  289.   if (!index ("led", kind))
  290.     io_error_msg
  291.       ("Incorrect postscript graph type %c (should be one of l, e, or c)",
  292.        kind);
  293.   if (!index ("mc", spectrum))
  294.     io_error_msg
  295.       ("Incorrect postscript color type %c (should be either m or c)",
  296.        spectrum);
  297.   sprint_line (&graph_term_cmd,
  298.            "postscript %c %c %s %d  # Postscript",
  299.            kind, spectrum, graph_quoted_str (font), pt_size);
  300.   set_line (&graph_output_file, file);
  301.   plot_fn = spew_for_ps;
  302. }
  303.  
  304.  
  305.  
  306. #ifdef __STDC__
  307. void
  308. graph_set_axis_title (int axis_c, char * title)
  309. #else
  310. void
  311. graph_set_axis_title (axis_c, title)
  312.      int axis_c;
  313.      char * title;
  314. #endif
  315. {
  316.   enum graph_axis axis = chr_to_axis (axis_c);
  317.   set_line (&graph_axis_title [axis], graph_quoted_str (title));
  318. }
  319.  
  320. #ifdef __STDC__
  321. void
  322. graph_set_logness (int axis_c, int explicit, int newval)
  323. #else
  324. void
  325. graph_set_logness (axis_c, explicit, newval)
  326.      int axis_c;
  327.      int explicit;
  328.      int newval;
  329. #endif
  330. {
  331.   enum graph_axis axis = chr_to_axis (axis_c);
  332.   static struct line msg_buf;
  333.  
  334.   if (!explicit)
  335.     newval = !graph_logness [axis];
  336.   else
  337.     newval = (newval > 0);
  338.  
  339.   graph_logness [axis] = newval;
  340.   sprint_line (&msg_buf, "%slogarithmic %s%s",
  341.            ((graph_logness [graph_x] || graph_logness [graph_y])
  342.         ? "" : "no"),
  343.            graph_logness [graph_x] ? "x" : "",
  344.            graph_logness [graph_y] ? "y" : "");
  345.   io_info_msg ("set %s", msg_buf.buf);
  346. }
  347.  
  348. #ifdef __STDC__
  349. void
  350. graph_check_range (char * val)
  351. #else
  352. void
  353. graph_check_range (val)
  354.      char * val;
  355. #endif
  356. {
  357.   if (says_default (val))
  358.     return;
  359.   while (isspace (*val)) ++val;
  360.   if (*val == '-') ++val;
  361.   while (isspace (*val)) ++val;
  362.   if (!isdigit (*val))
  363.     io_error_msg
  364.       ("Illegal range specifier %s (should be a numer or `def').", val);
  365.   else
  366.     {
  367.       while (*val)
  368.     if (isspace (*val) || isdigit (*val))
  369.       ++val;
  370.     else
  371.       break;
  372.       while (isspace (*val)) ++val;
  373.       if (*val == '.') ++val;
  374.       while (*val)
  375.     if (isspace (*val) || isdigit (*val))
  376.       ++val;
  377.     else
  378.       io_error_msg
  379.         ("Illegal range specifier %s (should be a numer or `def').", val);
  380.     }
  381.         
  382. }
  383.  
  384.  
  385. #ifdef __STDC__
  386. void
  387. graph_set_axis_lo (int axis_c, char * val)
  388. #else
  389. void
  390. graph_set_axis_lo (axis_c, val)
  391.      int axis_c;
  392.      char * val;
  393. #endif
  394. {
  395.   enum graph_axis axis = chr_to_axis (axis_c);
  396.   graph_check_range (val);
  397.   set_line (&graph_rng_lo [axis], val);
  398.   graph_axis_symbols [axis].lr = NON_ROW;
  399. }
  400.  
  401.  
  402. #ifdef __STDC__
  403. void
  404. graph_set_axis_hi (int axis_c, char * val)
  405. #else
  406. void
  407. graph_set_axis_hi (axis_c, val)
  408.      int axis_c;
  409.      char * val;
  410. #endif
  411. {
  412.   enum graph_axis axis = chr_to_axis (axis_c);
  413.   graph_check_range (val);
  414.   set_line (&graph_rng_hi [axis], val);
  415.   graph_axis_symbols [axis].lr = NON_ROW;
  416. }
  417.  
  418. #ifdef __STDC__
  419. void
  420. graph_set_axis_symbolic (int axis_c, struct rng * rng, int ordering_c) 
  421. #else
  422. void
  423. graph_set_axis_symbolic (axis_c, rng, ordering_c)
  424.      int axis_c;
  425.      struct rng * rng;
  426.      int ordering_c;
  427. #endif
  428. {
  429.   enum graph_axis axis = chr_to_axis (axis_c);
  430.   enum graph_ordering ordering = chr_to_graph_ordering (ordering_c);
  431.   int top = (rng->hr - rng->lr + 1) * (rng->hc - rng->lc + 1) - 1;
  432.   char buf [64];
  433.  
  434.   sprintf (buf, "%d.5", top);
  435.   graph_set_axis_lo (axis, "-0.5");
  436.   graph_set_axis_hi (axis, buf);
  437.   graph_axis_symbols [axis] = *rng;
  438.   graph_axis_ordering [axis] = ordering;
  439. }
  440.  
  441. #ifdef __STDC__
  442. void
  443. graph_set_axis_labels (int axis_c, struct rng * rng, int pair, int dir)
  444. #else
  445. void
  446. graph_set_axis_labels (axis_c, rng, dir, pair)
  447.      int axis_c;
  448.      struct rng * rng;
  449.      int pair;
  450.      int dir;
  451. #endif
  452. {
  453.   enum graph_pair_ordering order = chrs_to_graph_pair_ordering (pair, dir);
  454.   enum graph_axis axis = chr_to_axis (axis_c);
  455.   graph_axis_labels [axis] = *rng;
  456.   graph_axis_label_order [axis] = order;
  457. }
  458.  
  459. #ifdef __STDC__
  460. void
  461. graph_default_axis_labels (int axis_c)
  462. #else
  463. void
  464. graph_default_axis_labels (axis_c)
  465.      int axis_c;
  466. #endif
  467. {
  468.   enum graph_axis axis = chr_to_axis (axis_c);
  469.   graph_axis_labels [axis].lr = NON_ROW;
  470. }
  471.  
  472.  
  473.  
  474. static char * graph_plot_styles [] =
  475. {
  476.   "lines",
  477.   "points",
  478.   "linespoints",
  479.   "impulses",
  480.   "dots",
  481.    0
  482. };
  483.  
  484. #ifdef __STDC__
  485. int
  486. graph_check_style (char * name)
  487. #else
  488. int
  489. graph_check_style (name)
  490.      char * name;
  491. #endif
  492. {
  493.   int x =
  494.     words_member (graph_plot_styles, parray_len (graph_plot_styles), name);
  495.   if (x < 0)
  496.     io_error_msg
  497.       ("Invalid line style %s. (Try M-x describe-function set-graph-style).");
  498.   return x;
  499. }
  500.  
  501.  
  502. #ifdef __STDC__
  503. void
  504. graph_set_style (int data_set, char * style)
  505. #else
  506. void
  507. graph_set_style (data_set, style)
  508.      int data_set;
  509.      char * style;
  510. #endif
  511. {
  512.   int x = graph_check_style (style);
  513.   if ((data_set < 0) || (data_set >= NUM_DATASETS))
  514.     io_error_msg
  515.       ("set-graph-style -- data-set out of range: %d (should be in [0..%d])",
  516.        data_set, NUM_DATASETS);
  517.   set_line (&graph_style [data_set], graph_plot_styles [x]);
  518. }
  519.  
  520. #ifdef __STDC__
  521. void
  522. graph_set_data_title (int data_set, char * title)
  523. #else
  524. void
  525. graph_set_data_title (data_set, title)
  526.      int data_set;
  527.      char * title;
  528. #endif
  529. {
  530.   if ((data_set < 0) || (data_set >= NUM_DATASETS))
  531.     io_error_msg
  532.       ("set-graph-title -- data-set out of range: %d (should be in [0..%d])",
  533.        data_set, NUM_DATASETS);
  534.   set_line (&graph_title [data_set], title);
  535. }
  536.  
  537. #ifdef __STDC__
  538. void
  539. graph_set_data (int data_set, struct rng * rng, int pair, int dir)
  540. #else
  541. void
  542. graph_set_data (data_set, rng, pair, dir)
  543.      int data_set;
  544.      struct rng * rng;
  545.      int pair;
  546.      int dir;
  547. #endif
  548. {
  549.   enum graph_pair_ordering order = chrs_to_graph_pair_ordering (pair, dir);
  550.   if ((data_set < 0) || (data_set >= NUM_DATASETS))
  551.     io_error_msg
  552.       ("set-graph-data -- data-set out of range: %d (should be in [0..%d])",
  553.        data_set, NUM_DATASETS);
  554.   graph_data [data_set] = *rng;
  555.   graph_data_order [data_set] = order;
  556. }
  557.  
  558.  
  559.  
  560.  
  561. #ifdef __STDC__
  562. void
  563. graph_presets (void)
  564. #else
  565. void
  566. graph_presets ()
  567. #endif
  568. {
  569.   if (using_curses)
  570.     graph_postscript ("#plot.ps", 'd', 'm', "TimesRoman", 12);
  571.   else
  572.     graph_x11_mono ();
  573.   {
  574.     enum graph_axis axis;
  575.     for (axis = graph_x; axis < graph_num_axis; ++axis)
  576.       {
  577.     int axis_c = graph_axis_name [axis][0];
  578.     graph_logness [axis] = 0;
  579.     graph_set_axis_title (axis_c, "");
  580.     graph_set_axis_lo (axis_c, "def");
  581.     graph_set_axis_hi (axis_c, "def");
  582.     graph_set_axis_title (axis_c, "");
  583.     graph_default_axis_labels (axis_c);
  584.       }
  585.   }
  586. }
  587.  
  588.  
  589.  
  590.  
  591.  
  592. #ifdef __STDC__
  593. void
  594. graph_clear_datasets (void)
  595. #else
  596. void
  597. graph_clear_datasets ()
  598. #endif
  599. {
  600.   int x;
  601.   for (x = 0; x < NUM_DATASETS; ++x)
  602.     {
  603.       graph_set_style (x, "lines");
  604.       graph_set_data_title (x, "");
  605.       graph_data [x].lr = NON_ROW;
  606.     }
  607. }
  608.  
  609.  
  610. #ifdef __STDC__
  611. void
  612. init_graphing (void)
  613. #else
  614. void
  615. init_graphing ()
  616. #endif
  617. {
  618.   gnuplot_program = getenv ("GNUPLOT_PROG");
  619.   if (!gnuplot_program)
  620.     gnuplot_program = "gnuplot";
  621.   gnuplot_shell = getenv ("GNUPLOT_SHELL");
  622.   if (!gnuplot_shell)
  623.     gnuplot_shell = "/bin/sh";
  624.   rm_program = getenv ("RM_PROG");
  625.   if (!rm_program)
  626.     rm_program = "/bin/rm";
  627.   graph_presets ();
  628.   graph_clear_datasets ();
  629. }
  630.  
  631.  
  632. #ifdef __STDC__
  633. void
  634. graph_make_info (void)
  635. #else
  636. void
  637. graph_make_info ()
  638. #endif
  639. {
  640.   struct info_buffer * ib = find_or_make_info ("graphing-parameters");
  641.   enum graph_axis axis;
  642.  
  643.   clear_info (ib);
  644.  
  645.   {
  646.     print_info
  647.       (ib,
  648.        "");
  649.     print_info
  650.       (ib,
  651.        "Parameter        Value");
  652.     print_info
  653.       (ib,
  654.        "");
  655.  
  656.     print_info
  657.       (ib,
  658.        "output type        %s",
  659.        graph_term_cmd.buf);
  660.   }
  661.  
  662.   if (graph_output_file.buf[0])
  663.     print_info
  664.       (ib,
  665.        "output file        %s",
  666.        graph_output_file.buf);
  667.   
  668.   for (axis = graph_x; axis <= graph_y; ++axis)
  669.     print_info
  670.       (ib,
  671.        "%s-axis title        %s",
  672.        graph_axis_name [axis], graph_axis_title[axis].buf);
  673.  
  674.   {
  675.     print_info
  676.       (ib,
  677.        "logarithmic axes    %s",
  678.        (graph_logness [graph_x]
  679.     ? (graph_logness [graph_y] ? "x,y" : "x")
  680.     : (graph_logness [graph_y] ? "y" : "-neither-")));
  681.  
  682.   }
  683.   for (axis = graph_x; axis <= graph_y; ++axis)
  684.     {
  685.       if (graph_axis_symbols[axis].lr != NON_ROW)
  686.     print_info
  687.       (ib,
  688.            "%s-axis symbols    %s in %s",
  689.        graph_axis_name [axis],
  690.        graph_order_name [graph_axis_ordering [axis]],
  691.        range_name (&graph_axis_symbols [axis]));
  692.       else
  693.     print_info
  694.       (ib,
  695.         "%s-axis range        [%s..%s]",
  696.        graph_axis_name [axis],
  697.        graph_rng_lo [axis].buf, graph_rng_hi [axis].buf,
  698.        graph_rng_hi [axis].buf, graph_rng_hi [axis].buf);
  699.     }
  700.  
  701.   for (axis = graph_x; axis <= graph_y; ++axis)
  702.     {
  703.       if (graph_axis_labels[axis].lr != NON_ROW)
  704.     print_info
  705.       (ib,
  706.            "%s-axis labels        %s in %s",
  707.        graph_axis_name [axis],
  708.        graph_pair_order_name [graph_axis_label_order [axis]],
  709.        range_name (&graph_axis_labels [axis]));
  710.     }
  711.  
  712.   {
  713.     int x;
  714.     for (x = 0; x < NUM_DATASETS; ++x)
  715.       if (graph_data [x].lr != NON_ROW)
  716.       {
  717.     print_info (ib, "");
  718.     print_info (ib,"Data Set %d%s%s",
  719.             x,
  720.             graph_title[x].buf[0] ? " entitled " : "",
  721.             graph_title[x].buf);
  722.     print_info (ib,"  data for this set: %s in %s",
  723.             graph_pair_order_name [graph_data_order [x]],
  724.             range_name (&graph_data[x]));
  725.     print_info (ib,"  style for this set: %s",
  726.             graph_style[x].buf);
  727.     print_info (ib,"");
  728.       }
  729.   }
  730. }
  731.  
  732.  
  733.  
  734. #ifdef __STDC__
  735. static FILE *
  736. mk_tmp_file (struct line * line, char * dir, char * base)
  737. #else
  738. static FILE *
  739. mk_tmp_file (line, dir, base)
  740.      struct line * line;
  741.      char * dir;
  742.      char * base;
  743. #endif
  744. {
  745.   set_line (line, tmpnam (0));
  746.   return fopen (line->buf, "w");
  747. }
  748.  
  749.  
  750. #ifdef __STDC__
  751. void
  752. for_pairs_in (struct rng * rng, enum graph_pair_ordering order, fpi_thunk thunk, void * frame)
  753. #else
  754. void
  755. for_pairs_in (rng, order, thunk, frame)
  756.      struct rng * rng;
  757.      enum graph_pair_ordering order;
  758.      fpi_thunk thunk;
  759.      void * frame;
  760. #endif
  761. {
  762.   CELLREF r;
  763.   CELLREF c;
  764.   enum graph_pair_orientation ornt = order % graph_num_pair_orientations;
  765.   enum graph_ordering dir = ORDER_OF_PAIRS(order);
  766.   int r_inc = 1 + graph_ornt_row_magic [ornt];
  767.   int c_inc = 1 + graph_ornt_col_magic [ornt];
  768.   if (dir == graph_rows)
  769.     {
  770.       r = rng->lr;
  771.       while (1)
  772.     {
  773.       c = rng->lc;
  774.       while (1)
  775.         {
  776.           CELLREF y_r = r + graph_ornt_row_magic [ornt];
  777.           CELLREF y_c = c + graph_ornt_col_magic [ornt];
  778.           CELL * cell = find_cell (y_r, y_c);
  779.           thunk (frame, cell, y_r, y_c);
  780.           if ((rng->hc - c) < c_inc)
  781.         break;
  782.           c += c_inc;
  783.         }
  784.       if ((rng->hr - r) < r_inc)
  785.         break;
  786.       r += r_inc;
  787.     }
  788.     }
  789.   else
  790.     {
  791.       c = rng->lc;
  792.       while (1)
  793.     {
  794.       r = rng->lr;
  795.       while (1)
  796.         {
  797.           CELLREF y_r = r + graph_ornt_row_magic [ornt];
  798.           CELLREF y_c = c + graph_ornt_col_magic [ornt];
  799.           CELL * cell = find_cell (y_r, y_c);
  800.           thunk (frame, cell, y_r, y_c);
  801.           if ((rng->hr - r) < r_inc)
  802.         break;
  803.           r += r_inc;
  804.         }
  805.       if ((rng->hc - c) < c_inc)
  806.         break;
  807.       c += c_inc;
  808.     }
  809.     }
  810. }
  811.  
  812. struct write_tics_frame
  813. {
  814.   FILE * fp;
  815.   enum graph_axis axis;
  816.   enum graph_pair_orientation ornt;
  817.   int tic_cnt;
  818. };
  819.  
  820. #ifdef __STDC__
  821. static void
  822. write_tics_thunk (struct write_tics_frame * fr, CELL * cp, CELLREF r, CELLREF c)
  823. #else
  824. static void
  825. write_tics_thunk (fr, cp, r, c)
  826.      struct write_tics_frame * fr;
  827.      CELL * cp;
  828.      CELLREF r;
  829.      CELLREF c;
  830. #endif
  831. {
  832.   char * str = graph_quoted_str (print_cell (cp));
  833.   if (fr->tic_cnt)
  834.     fputs (", ", fr->fp);
  835.   fprintf (fr->fp, "%s ", str);
  836.   if (fr->ornt == graph_implicit)
  837.     fprintf (fr->fp, "%d", fr->tic_cnt);
  838.   else
  839.     {
  840.       CELLREF x_r = r - graph_ornt_row_magic [fr->ornt];
  841.       CELLREF x_c = c - graph_ornt_col_magic [fr->ornt];
  842.       
  843.       fprintf (fr->fp, "%s", print_cell (find_cell (x_r, x_c)));
  844.     }
  845.   ++fr->tic_cnt;
  846. }
  847.  
  848.  
  849. #ifdef __STDC__
  850. static void
  851. write_tics_command (FILE * fp, enum graph_axis axis, struct rng * rng, enum graph_pair_ordering order)
  852. #else
  853. static void
  854. write_tics_command (fp, axis, rng, order)
  855.      FILE * fp;
  856.      enum graph_axis axis;
  857.      struct rng * rng;
  858.      enum graph_pair_ordering order;
  859. #endif
  860. {
  861.   struct write_tics_frame fr;
  862.   fr.fp = fp;
  863.   fr.axis = axis;
  864.   fr.tic_cnt = 0;
  865.   fr.ornt = order % graph_num_pair_orientations;
  866.   fprintf (fp, "set %stics (", graph_axis_name[axis]);
  867.   for_pairs_in (rng, order, (fpi_thunk)write_tics_thunk, &fr);
  868.   fputs (")\n", fp);
  869. }
  870.  
  871. struct get_symbols_frame
  872. {
  873.   int symbols;
  874.   char ** names;
  875. };
  876.  
  877. #ifdef __STDC__
  878. static void
  879. get_symbols_thunk (struct get_symbols_frame * fr,
  880.            CELL * cell, CELLREF r, CELLREF c)
  881. #else
  882. static void
  883. get_symbols_thunk (fr, cell, r, c)
  884.      struct get_symbols_frame * fr;
  885.      CELL * cell;
  886.      CELLREF r;
  887.      CELLREF c;
  888. #endif
  889. {
  890.   fr->names = (char **)ck_realloc (fr->names,
  891.                    (fr->symbols + 1) * sizeof (char *));
  892.   fr->names [fr->symbols] = ck_savestr (print_cell (cell));
  893.   ++fr->symbols;
  894. }
  895.  
  896.  
  897. struct write_data_frame
  898. {
  899.   FILE * fp;
  900.   enum graph_pair_ordering ornt;
  901.   int data_cnt;
  902.   struct get_symbols_frame gsf;
  903. };
  904.  
  905. #ifdef __STDC__
  906. static void
  907. write_data_thunk (struct write_data_frame * fr,
  908.           CELL * y_cell, CELLREF r, CELLREF c) 
  909. #else
  910. static void
  911. write_data_thunk (fr, y_cell, r, c)
  912.      struct write_data_frame * fr;
  913.      CELL * y_cell;
  914.      CELLREF r;
  915.      CELLREF c;
  916. #endif
  917. {
  918.   if (!y_cell || !GET_TYP(y_cell))
  919.     return;
  920.   if (fr->ornt == graph_implicit)
  921.     fprintf (fr->fp, "%d ", fr->data_cnt);
  922.   else
  923.     {
  924.       CELLREF x_r = r - graph_ornt_row_magic [fr->ornt];
  925.       CELLREF x_c = c - graph_ornt_col_magic [fr->ornt];
  926.       CELL * x_cell = find_cell (x_r, x_c);
  927.       if (x_cell && GET_TYP(x_cell))
  928.     {
  929.       if (graph_axis_symbols [graph_x].lr == NON_ROW)
  930.         fprintf (fr->fp, "%s ", print_cell (x_cell));
  931.       else
  932.         {
  933.           char * key = print_cell (x_cell);
  934.           int x;
  935.           for (x = 0; x < fr->gsf.symbols; ++x)
  936.         if (stricmp (key, fr->gsf.names[x]))
  937.           {
  938.             fprintf (fr->fp, "%d ", x);
  939.             break;
  940.           }
  941.         }
  942.     }
  943.     }
  944.   fprintf (fr->fp, " %s\n", print_cell (y_cell));
  945.   ++fr->data_cnt;
  946. }
  947.  
  948.  
  949. #ifdef __STDC__
  950. static void
  951. spew_gnuplot (FILE  * fp, struct line * data_files, char * dir, char * dbase)
  952. #else
  953. static void
  954. spew_gnuplot (fp, data_files, dir, dbase)
  955.      FILE  * fp;
  956.      struct line * data_files;
  957.      char * dir;
  958.      char * dbase;
  959. #endif
  960. {
  961.   fprintf (fp, "set terminal %s\n", graph_term_cmd.buf);
  962.   fprintf (fp, "set output %s\n",
  963.        (graph_output_file.buf[0]
  964.         ? graph_quoted_str (graph_output_file.buf)
  965.         : ""));
  966.  
  967.   {
  968.     enum graph_axis axis;
  969.     for (axis = graph_x; axis <= graph_y; ++axis)
  970.       {
  971.     fprintf (fp, "set %slabel %s\n", graph_axis_name[axis],
  972.          (graph_axis_title[axis].buf[0]
  973.           ? graph_axis_title[axis].buf
  974.           : ""));
  975.  
  976.     fprintf (fp, "set %srange [%s:%s]\n",
  977.          graph_axis_name [axis],
  978.          (says_default (graph_rng_lo [axis].buf)
  979.           ? ""
  980.           : graph_rng_lo[axis].buf),
  981.          (says_default (graph_rng_hi [axis].buf)
  982.           ? ""
  983.           : graph_rng_hi[axis].buf));
  984.     if (   (graph_axis_symbols [axis].lr != NON_ROW)
  985.         && (graph_axis_labels [axis].lr == NON_ROW))
  986.       write_tics_command (fp, axis, &graph_axis_symbols [axis],
  987.                   PAIR_ORDER(graph_axis_ordering[axis],
  988.                            graph_implicit));
  989.     else if (graph_axis_labels [axis].lr != NON_ROW)
  990.       write_tics_command (fp, axis,
  991.                   &graph_axis_labels [axis],
  992.                   graph_axis_label_order [axis]);
  993.     else
  994.       fprintf (fp, "set %stics\n", graph_axis_name [axis]);
  995.       }
  996.     if (!(graph_logness[graph_x] && graph_logness[graph_y]))
  997.       fprintf (fp, "set nolog %s%s\n",
  998.            graph_logness[graph_x] ? "" : "x",
  999.            graph_logness[graph_y] ? "" : "y");
  1000.  
  1001.     if (graph_logness[graph_x] || graph_logness[graph_y])
  1002.       fprintf (fp, "set log %s%s\n",
  1003.            graph_logness[graph_x] ? "x" : "",
  1004.            graph_logness[graph_y] ? "y" : "");
  1005.   }
  1006.   {
  1007.     int need_comma = 0;
  1008.     int x;
  1009.     fprintf (fp, "plot ");
  1010.     for (x = 0; x < NUM_DATASETS; ++x)
  1011.       {
  1012.     init_line (&data_files [x]);
  1013.     if (graph_data [x].lr != NON_ROW)
  1014.       {
  1015.         FILE * df = mk_tmp_file (&data_files [x], dir, dbase);
  1016.         struct write_data_frame wdf;
  1017.         if (!df)
  1018.           {
  1019.         /* a small core leak here... */
  1020.         io_error_msg ("Error opening temp file `%s' for graph data.",
  1021.                   data_files [x].buf);
  1022.           }
  1023.         wdf.fp = df;
  1024.         wdf.ornt = graph_data_order [x] % graph_num_pair_orientations;
  1025.         wdf.data_cnt = 0;
  1026.         wdf.gsf.symbols = 0;
  1027.         wdf.gsf.names = 0;
  1028.         if (graph_axis_symbols [graph_x].lr != NON_ROW)
  1029.           for_pairs_in (&graph_axis_symbols [graph_x],
  1030.                 PAIR_ORDER (graph_axis_ordering [graph_x],
  1031.                     graph_implicit),
  1032.                 (fpi_thunk)get_symbols_thunk,
  1033.                 &wdf.gsf);
  1034.         for_pairs_in (&graph_data [x], graph_data_order [x],
  1035.               (fpi_thunk)write_data_thunk, &wdf);
  1036.         if (graph_axis_symbols [graph_x].lr != NON_ROW)
  1037.           {
  1038.         int x;
  1039.         for (x = 0; x < wdf.gsf.symbols; ++x)
  1040.           free (wdf.gsf.names[x]);
  1041.         ck_free (wdf.gsf.names);
  1042.           }
  1043.         fprintf (fp, "%s %s %s with %s",
  1044.              need_comma ? "," : "",
  1045.              graph_quoted_str (data_files [x].buf),
  1046.              graph_title [x].buf,
  1047.              graph_style [x].buf);
  1048.         need_comma = 1;
  1049.         fclose (df);
  1050.       }
  1051.       }
  1052.     fprintf (fp, "\n");
  1053.   }
  1054. }
  1055.  
  1056.  
  1057. #ifdef __STDC__
  1058. static void
  1059. graph_spew_with_parameters (struct line * shell_script, struct line *
  1060.                 gp_script, char * last_cmd, char * dir, char *
  1061.                 dbase, char * gbase, char * sbase, int run_gnuplot)
  1062. #else
  1063. static void
  1064. graph_spew_with_parameters (shell_script, gp_script, last_cmd, dir, dbase,
  1065.                 gbase, sbase, run_gnuplot)
  1066.      struct line * shell_script;
  1067.      struct line * gp_script;
  1068.      char * last_cmd;
  1069.      char * dir;
  1070.      char * dbase;
  1071.      char * gbase;
  1072.      char * sbase;
  1073.      int run_gnuplot;
  1074. #endif
  1075. {
  1076.   struct line data_files [NUM_DATASETS];
  1077.   FILE * fp;
  1078.   fp = mk_tmp_file (gp_script, dir, gbase);
  1079.   if (!fp)
  1080.     {
  1081.       /* coreleak filename */
  1082.       io_error_msg ("Error opening tmp file `%s' for plot script.",
  1083.             gp_script->buf);
  1084.     }
  1085.   spew_gnuplot (fp, data_files, dir, dbase);
  1086.   if (last_cmd)
  1087.     fputs (last_cmd, fp);
  1088.   if (sbase)
  1089.     {
  1090.       FILE * shfp;
  1091.       init_line (shell_script);
  1092.       shfp = mk_tmp_file (shell_script, dir, sbase);
  1093.       fprintf (shfp, "#!%s\n", gnuplot_shell);
  1094.       fputs ("\n", shfp);
  1095.       if (run_gnuplot)
  1096.     fprintf (shfp, "%s %s\n", gnuplot_program, gp_script->buf);
  1097.       fprintf (shfp, "%s %s %s  ",
  1098.            rm_program, gp_script->buf, shell_script->buf);
  1099.       {
  1100.     int x;
  1101.     for (x = 0; x < NUM_DATASETS; ++x)
  1102.       if (data_files[x].buf)
  1103.         fprintf (shfp, "%s ", data_files [x].buf);
  1104.       }
  1105.       fputs ("\n", shfp);
  1106.       fclose (shfp);
  1107.     }
  1108.   fclose (fp);
  1109. }
  1110.  
  1111.  
  1112. static FILE * pipe_to_gnuplot = 0;
  1113. static char * cleanup_script = 0;
  1114. static char * gnuplot_script = 0;
  1115.  
  1116. #ifdef __STDC__
  1117. static void death_to_gnuplot (void);
  1118. #else
  1119. static void death_to_gnuplot ();
  1120. #endif
  1121.  
  1122. #ifdef __STDC__
  1123. static void
  1124. gnuplot_exception (int fd)
  1125. #else
  1126. static void
  1127. gnuplot_exception (fd)
  1128.      int fd;
  1129. #endif
  1130. {
  1131.   death_to_gnuplot ();
  1132. }
  1133.  
  1134. #ifdef __STDC__
  1135. static void
  1136. gnuplot_writable (int fd)
  1137. #else
  1138. static void
  1139. gnuplot_writable (fd)
  1140.      int fd;
  1141. #endif
  1142. {
  1143.   FD_CLR (fd, &write_fd_set);
  1144.   file_write_hooks [fd].hook_fn = 0;
  1145.   fprintf (pipe_to_gnuplot, "\n\nload %s\n", graph_quoted_str (gnuplot_script));
  1146.   fflush (pipe_to_gnuplot);
  1147. }
  1148.  
  1149. #ifdef __STDC__
  1150. static void
  1151. ensure_gnuplot_pipe (void)
  1152. #else
  1153. static void
  1154. ensure_gnuplot_pipe ()
  1155. #endif
  1156. {
  1157.   if (!pipe_to_gnuplot)
  1158.     {
  1159.       pipe_to_gnuplot = popen (gnuplot_program, "w");
  1160.       if (!pipe_to_gnuplot)
  1161.     io_error_msg ("Can't popen gnuplot.");
  1162.     }
  1163.   if (gnuplot_script)
  1164.     {
  1165.       file_write_hooks [fileno (pipe_to_gnuplot)].hook_fn = gnuplot_writable;
  1166.       file_exception_hooks [fileno (pipe_to_gnuplot)].hook_fn = gnuplot_exception;
  1167.       FD_SET (fileno (pipe_to_gnuplot), &write_fd_set);
  1168.       FD_SET (fileno (pipe_to_gnuplot), &exception_fd_set);
  1169.     }
  1170. }
  1171.  
  1172. #ifdef __STDC__
  1173. static void
  1174. death_to_gnuplot (void)
  1175. #else
  1176. static void
  1177. death_to_gnuplot ()
  1178. #endif
  1179. {
  1180.   if (pipe_to_gnuplot)
  1181.     {
  1182.       int fd = fileno (pipe_to_gnuplot);
  1183.       file_write_hooks [fd].hook_fn = 0;
  1184.       file_exception_hooks [fd].hook_fn = 0;
  1185.       FD_CLR (fd, &write_fd_set);
  1186.       FD_CLR (fd, &exception_fd_set);
  1187.       pclose (pipe_to_gnuplot);
  1188.     }
  1189.   pipe_to_gnuplot = 0;
  1190.   if (cleanup_script)
  1191.     system (cleanup_script);
  1192.   if (cleanup_script)
  1193.     ck_free (cleanup_script);
  1194.   if (gnuplot_script)
  1195.     ck_free (gnuplot_script);
  1196. }
  1197.  
  1198.  
  1199.  
  1200.  
  1201.  
  1202. #ifdef __STDC__
  1203. static void
  1204. spew_for_x (void)
  1205. #else
  1206. static void
  1207. spew_for_x ()
  1208. #endif
  1209. {
  1210.   struct line shell_script;
  1211.   struct line gp_script;
  1212.   init_line (&shell_script);
  1213.   init_line (&gp_script);
  1214.   graph_spew_with_parameters (&shell_script, &gp_script, "pause -1\n", 0,
  1215.                   "#data", "#plot", "#sh", 0);
  1216.   splicen_line (&shell_script, " ", 1, 0);
  1217.   splicen_line (&shell_script, gnuplot_shell, strlen (gnuplot_shell), 0);
  1218.   if (cleanup_script)
  1219.     {
  1220.       system (cleanup_script);
  1221.       free (cleanup_script);
  1222.     }
  1223.   cleanup_script = shell_script.buf;
  1224.   if (gnuplot_script)
  1225.     free (gnuplot_script);
  1226.   gnuplot_script = gp_script.buf;
  1227.   ensure_gnuplot_pipe ();
  1228. }
  1229.  
  1230. #ifdef __STDC__
  1231. static void
  1232. spew_for_ps (void)
  1233. #else
  1234. static void
  1235. spew_for_ps ()
  1236. #endif
  1237. {
  1238.   struct line shell_script;
  1239.   struct line gp_script;
  1240.   init_line (&shell_script);
  1241.   init_line (&gp_script);
  1242.   graph_spew_with_parameters (&shell_script, &gp_script, 0, "", "#data",
  1243.                   "#plot", "#sh", 1); 
  1244.   splicen_line (&shell_script, " ", 1, 0);
  1245.   splicen_line (&shell_script, gnuplot_shell, strlen (gnuplot_shell), 0);
  1246.   system (shell_script.buf);
  1247.   free_line (&shell_script);
  1248.   free_line (&gp_script);
  1249. }
  1250.  
  1251. #ifdef __STDC__
  1252. void
  1253. graph_plot (void)
  1254. #else
  1255. void
  1256. graph_plot ()
  1257. #endif
  1258. {
  1259.   plot_fn ();
  1260. }
  1261.  
  1262.